import java.util.ArrayList;
import java.util.List;

/**
 * 234. 回文链表
 */
public class Solution_234 {
    /**
     * 方法二：快慢指针
     * <p>
     * 时间复杂度：O(N)
     * <p>
     * 空间复杂度：O(1)
     */
    public boolean isPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }

        // 找到前半部分链表的尾节点并反转后半部分链表
        ListNode firstHalfEnd = endOfFirstHalf(head);
        ListNode secondHalfStart = reverseList(firstHalfEnd.next);

        // 判断是否回文
        ListNode p1 = head, p2 = secondHalfStart;
        boolean ans = true;
        while (ans && p2 != null) {
            if (p1.val != p2.val) {
                ans = false;
            }
            p1 = p1.next;
            p2 = p2.next;
        }

        // 还原链表并返回结果，如果无需还原可省略
        firstHalfEnd.next = reverseList(secondHalfStart);
        return ans;
    }

    /**
     * 反转链表
     */
    private ListNode reverseList(ListNode head) {
        ListNode pre = null, cur = head;
        while (cur != null) {
            ListNode nextNode = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nextNode;
        }
        return pre;
    }

    /**
     * 找到链表前半部分的尾节点
     */
    private ListNode endOfFirstHalf(ListNode head) {
        ListNode fast = head, slow = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    /**
     * 方法一：将值复制到数组中后用双指针法
     * <p>
     * 时间复杂度：O(N)
     * <p>
     * 空间复杂度：O(N)
     */
    public boolean isPalindrome1(ListNode head) {
        List<Integer> list = new ArrayList<>();

        // 将链表的值复制到数组中
        ListNode cur = head;
        while (cur != null) {
            list.add(cur.val);
            cur = cur.next;
        }

        // 使用双指针判断是否回文
        int left = 0, right = list.size() - 1;
        while (left < right) {
            // 注意这里要用 equals
            if (!list.get(left).equals(list.get(right))) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }

    public static void main(String[] args) {
        Solution_234 solution = new Solution_234();
        // 测试 1
        ListNode head = new ListNode(1);
        head.next = new ListNode(500);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(500);
        head.next.next.next.next = new ListNode(1);
        boolean ans = solution.isPalindrome(head);
        System.out.println(ans);
        // 测试 2
        head = new ListNode(1, new ListNode(2));
        ans = solution.isPalindrome(head);
        System.out.println(ans);
    }
}
